feat(tui): display main agent TodoWrite items above input field#120
feat(tui): display main agent TodoWrite items above input field#120
Conversation
Greptile OverviewGreptile SummaryThis PR adds a “Plan” section to the minimal session TUI that shows the main agent’s TodoWrite items above the input area. It introduces main-agent todo types stored on Key integration points:
Issues to address before merge are mainly around stale todo state (TodoWrite calls that clear/omit items don’t currently clear UI state) and layout safety when the scrollable content height exceeds its allocation (todo section can render out of bounds/overlap). Confidence Score: 3/5
|
| Filename | Overview |
|---|---|
| src/cortex-tui/src/app/mod.rs | Re-exports new main-agent todo types from state module. |
| src/cortex-tui/src/app/state.rs | Adds MainAgentTodoItem/Status types and stores main_agent_todos in AppState with basic update/clear helpers. |
| src/cortex-tui/src/runner/event_loop/tools.rs | Intercepts TodoWrite calls to parse/update main-agent todos before tool execution; current parsing/update logic can leave stale todos on empty/unsupported formats. |
| src/cortex-tui/src/views/minimal_session/rendering.rs | Adds render_main_agent_todos to display main-agent plan with status markers and strikethrough for completed items. |
| src/cortex-tui/src/views/minimal_session/view.rs | Integrates main-agent todo rendering above status/input and reserves extra height; current placement can render out of bounds if content height exceeds allocation. |
Sequence Diagram
sequenceDiagram
participant LLM as Main agent (LLM)
participant EL as EventLoop
participant AS as AppState
participant TR as ToolRegistry
participant UI as MinimalSessionView
LLM->>EL: ToolCall: TodoWrite(args)
EL->>AS: handle_main_agent_todo_write(args)
Note over AS: Updates main_agent_todos for immediate display
EL->>TR: execute("TodoWrite", args) (async)
UI->>AS: has_main_todos()/main_agent_todos
UI-->>UI: render_main_agent_todos()
TR-->>EL: ToolEvent::Completed/Failed
EL-->>AS: (no todo update on completion)
UI->>AS: reads latest state on next render
| /// Handle main agent's TodoWrite tool call. | ||
| /// Parses the todos argument and updates app_state for real-time display. | ||
| fn handle_main_agent_todo_write(&mut self, args: &serde_json::Value) { |
There was a problem hiding this comment.
Todo list never clears
handle_main_agent_todo_write() only updates app_state.main_agent_todos when the parsed todos vector is non-empty (e.g., if !todos.is_empty() { ... }). This means a valid TodoWrite call that intentionally sends an empty list (or an empty/whitespace string) will not clear the UI, leaving stale todos displayed. Consider explicitly clearing on empty input (e.g., call clear_main_todos() when todos parses but is empty) so the “empty state: no todo section shown” acceptance criterion is actually met.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cortex-tui/src/runner/event_loop/tools.rs
Line: 651:653
Comment:
**Todo list never clears**
`handle_main_agent_todo_write()` only updates `app_state.main_agent_todos` when the parsed `todos` vector is non-empty (e.g., `if !todos.is_empty() { ... }`). This means a valid TodoWrite call that intentionally sends an empty list (or an empty/whitespace string) will *not* clear the UI, leaving stale todos displayed. Consider explicitly clearing on empty input (e.g., call `clear_main_todos()` when `todos` parses but is empty) so the “empty state: no todo section shown” acceptance criterion is actually met.
How can I resolve this? If you propose a fix, please make it concise.| // Try to parse as string format first (numbered list) | ||
| if let Some(todos_str) = args.get("todos").and_then(|v| v.as_str()) { | ||
| let todos: Vec<MainAgentTodoItem> = todos_str | ||
| .lines() | ||
| .filter_map(|line| { | ||
| // Parse lines like "1. [completed] First task" |
There was a problem hiding this comment.
Bracket parsing can drop todos
The string-format parser assumes each line contains [ and ] and uses line.find(']')/line.find('[') to slice status/content. If the main agent ever emits a numbered todo line without bracketed status (or with additional ] earlier in the content), that todo will be silently skipped, potentially resulting in an empty parsed list and (due to the non-empty guard) no state update. This causes the UI to show stale items even though a new TodoWrite was issued. A more robust parse should handle missing/unknown status and still capture the content.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cortex-tui/src/runner/event_loop/tools.rs
Line: 657:662
Comment:
**Bracket parsing can drop todos**
The string-format parser assumes each line contains `[` and `]` and uses `line.find(']')`/`line.find('[')` to slice status/content. If the main agent ever emits a numbered todo line without bracketed status (or with additional `]` earlier in the content), that todo will be silently skipped, potentially resulting in an empty parsed list and (due to the non-empty guard) no state update. This causes the UI to show stale items even though a new TodoWrite was issued. A more robust parse should handle missing/unknown status and still capture the content.
How can I resolve this? If you propose a fix, please make it concise.| // 4.5. Main agent todos (if any) - above status indicator | ||
| if self.app_state.has_main_todos() { | ||
| let todo_lines = | ||
| render_main_agent_todos(&self.app_state.main_agent_todos, area.width, &self.colors); | ||
| let todo_area = Rect::new(area.x, next_y, area.width, main_todos_height); |
There was a problem hiding this comment.
Todo area can overlap
todo_area is rendered unconditionally at next_y with height main_todos_height, but next_y is derived from content_end_y + 1 where content_end_y comes from actual_content_height. If actual_content_height is larger than the allocated available_height (e.g., due to long welcome/messages rendering), next_y can already be past the bottom of area, and the todo section will render out-of-bounds/overlap subsequent regions. This is particularly easy to hit because adding main_todos_height reduces available_height but doesn’t constrain actual_content_height to that allocation.
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/cortex-tui/src/views/minimal_session/view.rs
Line: 613:617
Comment:
**Todo area can overlap**
`todo_area` is rendered unconditionally at `next_y` with height `main_todos_height`, but `next_y` is derived from `content_end_y + 1` where `content_end_y` comes from `actual_content_height`. If `actual_content_height` is larger than the allocated `available_height` (e.g., due to long welcome/messages rendering), `next_y` can already be past the bottom of `area`, and the todo section will render out-of-bounds/overlap subsequent regions. This is particularly easy to hit because adding `main_todos_height` reduces `available_height` but doesn’t constrain `actual_content_height` to that allocation.
How can I resolve this? If you propose a fix, please make it concise.- Add MainAgentTodoItem and MainAgentTodoStatus types in state.rs - Add update_main_todos, clear_main_todos, has_main_todos methods - Parse TodoWrite tool calls in spawn_tool_execution for real-time display - Add render_main_agent_todos function with styled output - Integrate todos display in minimal session view layout - Re-export new types from app module
441b95b to
e95b74a
Compare
Summary
This PR implements a TodoWrite display feature for the main Cortex agent in the TUI. When the main agent uses the TodoWrite tool, the todo list is displayed above the input field, providing real-time visibility into the agent's planned tasks.
Changes
State Management (
src/cortex-tui/src/app/state.rs)MainAgentTodoItemstruct withcontentandstatusfieldsMainAgentTodoStatusenum (Pending,InProgress,Completed)main_agent_todos: Vec<MainAgentTodoItem>field toAppStateupdate_main_todos(),clear_main_todos(),has_main_todos()Tool Event Handling (
src/cortex-tui/src/runner/event_loop/tools.rs)spawn_tool_execution()1. [status] content) and array formatRendering (
src/cortex-tui/src/views/minimal_session/rendering.rs)render_main_agent_todos()functionModifier::CROSSED_OUT)View Integration (
src/cortex-tui/src/views/minimal_session/view.rs)Visual Example
Acceptance Criteria
Testing
cargo check -p cortex-tuipasses with no errors